Árboles de desición

EL presente laboratorio expone el análisis de los árboles de decisión. Se presenta:

  1. Paquetes y funciones
  2. Datos del laboratorio (fuentes de datos)
  3. Análisis descriptivo de las variables
  4. Prtición de datos
  5. Árboles de clasificación
  6. Árboles de desición
  7. Estimación del modelo
  8. Evaluación del modelo
  9. Re ajuste del modelo

Datos del laboratorio

Estos son los datos que se utilizarán en el laboratorio

El titanic

Sobre el archivo de datos

El propósito del siguiente conjunto de datos titanic es predecir que personas son más propensas a sobrevivir la colisión con el iceberg. El conjunto de datos contiene 13 variables y 1309 observaciones.

## 'data.frame':    1309 obs. of  13 variables:
##  $ X        : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ pclass   : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ survived : int  1 1 0 0 0 1 1 0 1 0 ...
##  $ name     : Factor w/ 1307 levels "Abbing, Mr. Anthony",..: 22 24 25 26 27 31 46 47 51 55 ...
##  $ sex      : Factor w/ 2 levels "female","male": 1 2 1 2 1 2 1 2 1 2 ...
##  $ age      : num  29 0.917 2 30 25 ...
##  $ sibsp    : int  0 1 1 1 1 0 1 0 2 0 ...
##  $ parch    : int  0 2 2 2 2 0 0 0 0 0 ...
##  $ ticket   : Factor w/ 929 levels "110152","110413",..: 188 50 50 50 50 125 93 16 77 826 ...
##  $ fare     : num  211 152 152 152 152 ...
##  $ cabin    : Factor w/ 187 levels "","A10","A11",..: 45 81 81 81 81 151 147 17 63 1 ...
##  $ embarked : Factor w/ 4 levels "","C","Q","S": 4 4 4 4 4 4 4 4 4 2 ...
##  $ home.dest: Factor w/ 370 levels "","?Havana, Cuba",..: 310 232 232 232 232 238 163 25 23 230 ...

Arreglo y limpieza de los datos

Los datos no están ordenados aleatoriamente sino secuencialmente de acuerdo a la variable categórica de interés. Esto es un problema importante y se debe corregir antes de dividir los datos en entrenamiento y test. Para desordenar la lista de observaciones, se puede usar la función sample()

## [1]   57  774  796 1044  681  920

Hacemos una limpieza de los datos…

Existen valores NA’s, por lo tanto deben ser eliminados. Prescindir de variables innecesarias Crear-convertir variables a tipo factor de ser necesario (e.g., pclass y survived)

## Observations: 1,045
## Variables: 9
## $ X        <int> 57, 774, 920, 430, 1012, 476, 653, 1295, 79, 517, 312...
## $ pclass   <fct> Upper, Lower, Lower, Middle, Lower, Middle, Lower, Lo...
## $ survived <fct> Yes, No, No, No, No, No, No, No, Yes, No, Yes, No, No...
## $ sex      <fct> male, male, male, male, female, female, male, male, f...
## $ age      <dbl> 36.0, 42.0, 18.5, 44.0, 19.0, 26.0, 23.0, 28.5, 64.0,...
## $ sibsp    <int> 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,...
## $ parch    <int> 2, 0, 0, 0, 0, 1, 0, 0, 2, 2, 1, 0, 0, 0, 0, 1, 0, 0,...
## $ fare     <dbl> 120.0000, 8.6625, 7.2292, 13.0000, 16.1000, 26.0000, ...
## $ embarked <fct> S, S, C, S, S, S, S, S, C, S, S, S, S, S, S, S, S, S,...

Wine

Los datos que analizamos son datos de vinos blancos de Portugal. El conjunto de datos se puede acceder en Repositorio de Datos de Aprendizaje Automático de UCI http://archive.ics.uci.edu/ml

url  <-"http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv"
wine <- read.table(file=url, header = T, sep=";")
knitr::kable(head(wine),caption = "Resumen de datos")
Resumen de datos
fixed.acidity volatile.acidity citric.acid residual.sugar chlorides free.sulfur.dioxide total.sulfur.dioxide density pH sulphates alcohol quality
7.0 0.27 0.36 20.7 0.045 45 170 1.0010 3.00 0.45 8.8 6
6.3 0.30 0.34 1.6 0.049 14 132 0.9940 3.30 0.49 9.5 6
8.1 0.28 0.40 6.9 0.050 30 97 0.9951 3.26 0.44 10.1 6
7.2 0.23 0.32 8.5 0.058 47 186 0.9956 3.19 0.40 9.9 6
7.2 0.23 0.32 8.5 0.058 47 186 0.9956 3.19 0.40 9.9 6
8.1 0.28 0.40 6.9 0.050 30 97 0.9951 3.26 0.44 10.1 6
str(wine)
## 'data.frame':    4898 obs. of  12 variables:
##  $ fixed.acidity       : num  7 6.3 8.1 7.2 7.2 8.1 6.2 7 6.3 8.1 ...
##  $ volatile.acidity    : num  0.27 0.3 0.28 0.23 0.23 0.28 0.32 0.27 0.3 0.22 ...
##  $ citric.acid         : num  0.36 0.34 0.4 0.32 0.32 0.4 0.16 0.36 0.34 0.43 ...
##  $ residual.sugar      : num  20.7 1.6 6.9 8.5 8.5 6.9 7 20.7 1.6 1.5 ...
##  $ chlorides           : num  0.045 0.049 0.05 0.058 0.058 0.05 0.045 0.045 0.049 0.044 ...
##  $ free.sulfur.dioxide : num  45 14 30 47 47 30 30 45 14 28 ...
##  $ total.sulfur.dioxide: num  170 132 97 186 186 97 136 170 132 129 ...
##  $ density             : num  1.001 0.994 0.995 0.996 0.996 ...
##  $ pH                  : num  3 3.3 3.26 3.19 3.19 3.26 3.18 3 3.3 3.22 ...
##  $ sulphates           : num  0.45 0.49 0.44 0.4 0.4 0.44 0.47 0.45 0.49 0.45 ...
##  $ alcohol             : num  8.8 9.5 10.1 9.9 9.9 10.1 9.6 8.8 9.5 11 ...
##  $ quality             : int  6 6 6 6 6 6 6 6 6 6 ...

Funciones para crear árboles de decisión

Existen varios algoritmos implementados en R para llevar a cabo los árboles de decisión: ID3, CART, C4.5 C5.0, CHAID.

Es importante saber que existen variadas implementaciones (librerías) de árboles de decisión en R como por ejemplo: rpart, tree, party, ctree, etc. Algunas se diferencias en las heurísticas utilizadas para el proceso de poda del árbol y otras manejan un componente probabilísto internamente.

Un ejemplo del esquema general para implementación.

# x <- cbind(x_train,y_train)

# fit <- rpart(y_train ~ ., data = x,method="class")
# summary(fit)

# predicted= predict(fit,x_test)

rpart

https://www.rdocumentation.org/packages/rpart/versions/4.1-15/topics/rpart

# rpart(formula, data, weights, subset, na.action = na.rpart, method,
#      model = FALSE, x = FALSE, y = TRUE, parms, control, cost, …)

tree

https://www.rdocumentation.org/packages/tree/versions/1.0-40

# tree(formula, data, weights, subset,
#     na.action = na.pass, control = tree.control(nobs, ...),
#     method = "recursive.partition",
#     split = c("deviance", "gini"),
#     model = FALSE, x = FALSE, y = TRUE, wts = TRUE, ...)

party

https://www.rdocumentation.org/packages/partykit/versions/1.2-4/topics/party

# party(node, data, fitted = NULL, terms = NULL, names = NULL, 
#    info = NULL)

ctree

https://www.rdocumentation.org/packages/partykit/versions/1.2-4/topics/ctree

# ctree(formula, data, subset, weights, na.action = na.pass, offset, cluster, 
#     control = ctree_control(…), ytrafo = NULL, 
#    converged = NULL, scores = NULL, doFit = TRUE, …)

Árboles de clasificación

Estadísticas descriptivas

En los análisis, realizar análisis descriptivos para la variable dependiente Análisis descriptivos para las variables dependientes

Separación de datos: entranamiento y validación

Antes de entrenar el modelo vamos a dividir el conjunto de datos en entrenamiento y test. La práctica común es 80-20. Crearemos una función con este propósito.

##   pclass survived    sex age sibsp parch     fare embarked
## 1  Lower       No   male  17     0     0   7.8958        S
## 2 Middle       No female  22     0     0  21.0000        S
## 3  Lower       No   male  22     0     0   9.3500        S
## 4 Middle      Yes   male   2     1     1  23.0000        S
## 5  Lower       No   male  18     0     0   7.7500        S
## 6  Upper      Yes female  26     1     0 136.7792        C
## [1] 836   8
## [1] 209   8

Conjunto de entrenamiento = 1046 filas (instancias) Conjunto de test = 262 filas (instancias)

Ahora verificamos el proceso de aleatoriedad a través de las funciones prop.table() combinada con table()

prop.table(table(data_train$survived))
## 
##        No       Yes 
## 0.5980861 0.4019139
prop.table(table(data_test$survived))
## 
##        No       Yes 
## 0.5645933 0.4354067

Construcción del modelo

El comando para generar un modelo de árbol de decisión, usando la librería rpart lleva el mismo nombre.

Cada nodo muestra

La clase predecida (died o survived), La probabilidad predecida de survival, El porcentaje de observaciones en el nodo.

Ahora probemos con las opciones 1 y 9.

Opción 1

Opción 9

Los árboles de decisión requieren muy poca preparación de datos. Particularmente, no requieren escalamiento de atributos o centrado.

Por defecto, rpart() use la medida de Gini para la división de los nodos.

Estimación (predicción) del modelo

El modelo ha sido entrenado y ahora puede ser usado para predecir nuevas instancias en el conjunto de datos de test. Para esto se usa la función predict().

#Arguments:
#- fitted_model: This is the object stored after model estimation. 
#- df: Data frame used to make the prediction
#- type: Type of prediction         
#    - 'class': for classification          
#    - 'prob': to compute the probability of each class         
#    - 'vector': Predict the mean response at the node level    

Contabilizar la coincidencia entre las observaciones de test y los valores predecidos (matriz de confusión).

##      predict_unseen
##        No Yes
##   No  107  11
##   Yes  33  58

¿Que podemos concluir de esto?

Rendimiento del modelo

A partir de la matriz de confusión es posible calcular un medida de rendimiento del modelo. La matriz de confusión es utilizada en casos de clasificación.

## [1] "Precisión de la prueba 0.789473684210526"

Ajustar los hyper-parámetros

Para incluir restricciones definidas por el usuario respecto a cómo elaborar el árbol de decisión se puede utilizar el comando rpart.control() de la librería rpart.

#rpart.control(minsplit = 20, minbucket = round(minsplit/3), maxdepth = 30)
#Arguments:
#-minsplit: Set the minimum number of observations in the node before the algorithm perform a split
#-minbucket:  Set the minimum number of observations in the final node i.e. the leaf
#-maxdepth: Set the maximum depth of any node of the final tree. The root node is treated a depth 0

Vamos a modificar el ejemplo anterior. Para ello vamos a constuir una función que encapsule el cáculo de la precisión del modelo.

Ahora, vamos a ajustar los parámetros para intentar mejor el rendimiento del modelo sobre los valores por defecto. La precisión que obtuvimos previamente fue de 0.78.

## [1] 0.7894737

En efecto hemos mejorado ligeramente la estimación de 0.78 a 0.79. Como habíamos revisado anteriormente, lo ideal sería aplicar un proceso de validación cruzada para ajustar correctamente y encontrar así la mejor combinación.

Árboles de regresión

Queremos predecir la calidad del vino, Quality según otras características del mismo:

acidity sugar content chlorides sulfur alcohol pH density

Estadísticas descriptivas

Explorando los datos

Parece que Quality sigue una distribución más o menos Normal.

Veamos las densidades

Separación de datos: entranamiento y validación

No es necesario el procesamiento previo de datos para emplear un modelo de árbol de decisión. Para los datos de entrenamiento (training) y prueba (test) vamos a tomar una muestra al azar con una proporción del 75% y del 25% respectivamente.

## [1] 3750

Estimación (predicción) del modelo

## n= 3750 
## 
## node), split, n, deviance, yval
##       * denotes terminal node
## 
##  1) root 3750 2920.95600 5.881067  
##    2) alcohol< 10.85 2351 1394.32200 5.603998  
##      4) volatile.acidity>=0.2375 1483  718.65410 5.395819  
##        8) free.sulfur.dioxide< 17.5 204  100.87750 5.024510 *
##        9) free.sulfur.dioxide>=17.5 1279  585.16500 5.455043  
##         18) alcohol< 10.01667 951  359.84230 5.362776 *
##         19) alcohol>=10.01667 328  193.75300 5.722561 *
##      5) volatile.acidity< 0.2375 868  501.58870 5.959677 *
##    3) alcohol>=10.85 1399 1042.86200 6.346676  
##      6) free.sulfur.dioxide< 10.5 73   77.75342 5.315068 *
##      7) free.sulfur.dioxide>=10.5 1326  883.14400 6.403469  
##       14) alcohol< 11.775 660  422.58180 6.218182 *
##       15) alcohol>=11.775 666  415.44890 6.587087 *

Veamos el árbol

Rendimiento - evaluación del modelo

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   5.025   5.363   5.960   5.882   6.218   6.587
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   3.000   5.000   6.000   5.868   6.000   8.000

Otra forma de analizar el rendimiento del modelo es considerar cómo de diferente, en promedio, ha caído la predicción del valor real: Error absoluto medio (MAE).

## [1] 0.5987078

Un Error Absoluto Medio del 59% es aceptable.